package com.uwlaser.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.uwlaser.base.PageInfo;
import com.uwlaser.base.QueryHelpMybatisPlus;
import com.uwlaser.base.impl.CommonServiceImpl;
import com.uwlaser.domain.*;
import com.uwlaser.service.FactoryShiftHistoryService;
import com.uwlaser.service.FactoryShiftService;
import com.uwlaser.service.FactoryShiftTimeService;
import com.uwlaser.service.dto.FactoryShiftDto;
import com.uwlaser.service.dto.FactoryShiftQueryParam;
import com.uwlaser.service.mapper.FactoryModelMapper;
import com.uwlaser.service.mapper.FactoryShiftMapper;
import com.uwlaser.service.mapper.FactoryShiftTimeMapper;
import com.uwlaser.utils.ConvertUtil;
import com.uwlaser.utils.PageUtil;
import lombok.AllArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author huangpan
 * @date 2022-12-02
 */
@Service
@AllArgsConstructor
// @CacheConfig(cacheNames = FactoryShiftService.CACHE_KEY)
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class FactoryShiftServiceImpl extends CommonServiceImpl<FactoryShiftMapper, FactoryShift> implements FactoryShiftService {

    // private final RedisUtils redisUtils;
    private final FactoryShiftMapper factoryShiftMapper;

    private final FactoryShiftTimeService factoryShiftTimeService;

    private final FactoryModelMapper factoryModelMapper;

    private final FactoryShiftTimeMapper factoryShiftTimeMapper;

    private final FactoryShiftHistoryService factoryShiftHistoryService;


    @Override
    public PageInfo<FactoryShiftDto> queryAll(FactoryShiftQueryParam query, Pageable pageable) {
        IPage<FactoryShift> queryPage = PageUtil.toMybatisPage(pageable);
        IPage<FactoryShift> page = factoryShiftMapper.selectPage(queryPage, QueryHelpMybatisPlus.getPredicate(query));
        return ConvertUtil.convertPage(page, FactoryShiftDto.class);
    }

    @Override
    public List<FactoryShiftDto> queryAll(FactoryShiftQueryParam query) {
        return ConvertUtil.convertList(factoryShiftMapper.selectList(QueryHelpMybatisPlus.getPredicate(query)), FactoryShiftDto.class);
    }

    @Override
    public FactoryShift getById(Integer id) {
        return factoryShiftMapper.selectById(id);
    }

    @Override
    // @Cacheable(key = "'id:' + #p0")
    public FactoryShiftDto findById(Integer id) {
        return ConvertUtil.convert(getById(id), FactoryShiftDto.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insert(FactoryShiftDto resources) {
        FactoryShift entity = ConvertUtil.convert(resources, FactoryShift.class);
        //查看编码是否存在
        List<FactoryShift> factoryShifts = factoryShiftMapper.selectList(new LambdaQueryWrapper<FactoryShift>()
                .eq(FactoryShift::getShiftCode, resources.getShiftCode()));
        if (!CollectionUtils.isEmpty(factoryShifts)) {
            throw new RuntimeException("当前" + resources.getShiftCode() + "编码已存在");
        }
        //获取该模型班次
        List<FactoryShift> factoryShifts1 = factoryShiftMapper.selectList(new LambdaQueryWrapper<FactoryShift>()
                .eq(FactoryShift::getTemplateCode, resources.getTemplateCode()));
        //判断该时间段是否存在班次
        verificationData(factoryShifts1, resources);
        int insert = factoryShiftMapper.insert(entity);
        //新增班次停机信息
        List<FactoryShiftTime> factoryShiftTimes = resources.getFactoryShiftTimes();
        if (!CollectionUtils.isEmpty(factoryShiftTimes)) {
            factoryShiftTimes.forEach(f -> {
                f.setShiftId(entity.getId());
            });
            factoryShiftTimeService.saveBatch(factoryShiftTimes);
        }

        return insert;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateById(FactoryShiftDto resources) {
        FactoryShift entity = ConvertUtil.convert(resources, FactoryShift.class);
        FactoryShift factoryShift = factoryShiftMapper.selectById(resources.getId());
        if (!factoryShift.getShiftCode().equals(resources.getShiftCode())) {
            //查看编码是否存在
            List<FactoryShift> factoryShifts = factoryShiftMapper.selectList(new LambdaQueryWrapper<FactoryShift>()
                    .eq(FactoryShift::getShiftCode, resources.getShiftCode()));
            if (!CollectionUtils.isEmpty(factoryShifts)) {
                throw new RuntimeException("当前" + resources.getShiftCode() + "编码已存在");
            }
        }
        //查看时间段是否存在
        //获取该模型班次
        List<FactoryShift> factoryShifts1 = factoryShiftMapper.selectList(new LambdaQueryWrapper<FactoryShift>()
                .eq(FactoryShift::getTemplateCode, resources.getTemplateCode()).ne(FactoryShift::getId, resources.getId()));
        //判断该时间段是否存在班次
        verificationData(factoryShifts1, resources);
        //添加班次历史数据
        factoryShiftHistoryService.add(resources.getTemplateCode());
        int ret = factoryShiftMapper.updateById(entity);
        // delCaches(resources.id);
        return ret;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int removeByIds(Set<Integer> ids) {
        // delCaches(ids);
        //获取要删除的班次信息
        List<FactoryShift> factoryShifts = factoryShiftMapper.selectList(new LambdaQueryWrapper<FactoryShift>()
                .in(FactoryShift::getId, ids));
        //删除非上班时间
        factoryShiftTimeService.remove(new LambdaQueryWrapper<FactoryShiftTime>()
                .in(FactoryShiftTime::getShiftId, ids));
        //添加班次历史数据
        factoryShiftHistoryService.add(factoryShifts.get(0).getTemplateCode());
        return factoryShiftMapper.deleteBatchIds(ids);
    }

    @Override
    public FactoryShiftDto getClasses(FactoryShiftDto factoryShiftDto) {
        //获取工厂结构
        List<FactoryModel> factoryModelList = factoryModelMapper.selectList(new LambdaQueryWrapper<FactoryModel>().in(FactoryModel::getModelType, "0", "1", "2"));
        //根据模组类型获取班次信息
        List<FactoryShift> data = getData(factoryModelList, factoryShiftDto.getTemplateCode(), "3");
        if (CollectionUtils.isEmpty(data)) {
            throw new RuntimeException("还没有班次信息,请前往设置!");
        }
        FactoryShift production = getProduction(data);
        //获取当前时间段班次
        FactoryShiftDto convert = ConvertUtil.convert(production, FactoryShiftDto.class);
        //获取班次停机信息
        convert.setFactoryShiftTimes(factoryShiftTimeMapper.selectList(new LambdaQueryWrapper<FactoryShiftTime>()
                .eq(FactoryShiftTime::getShiftId, convert.getId())));
        return convert;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int removeById(Integer id) {
        Set<Integer> set = new HashSet<>(1);
        set.add(id);
        return this.removeByIds(set);
    }

    /**
     * 获取班次信息
     */
    public List<FactoryShift> getData(List<FactoryModel> factoryModelList, String templateCode, String ModelType) {
        //获取班次信息
        List<FactoryShift> factoryShifts = factoryShiftMapper.selectList(new LambdaQueryWrapper<FactoryShift>()
                .eq(FactoryShift::getTemplateCode, templateCode).eq(FactoryShift::getIsDisable, "0"));
        if (CollectionUtils.isEmpty(factoryShifts)) {
            if (ModelType.equals("0")) {
                return null;
            }
            //获取当前类型详情信息
            List<FactoryModel> collect = factoryModelList.stream()
                    .filter(f -> f.getModelCode().equals(templateCode)).collect(Collectors.toList());
            Integer pid = collect.get(0).getPid();
            List<FactoryModel> collect1 = factoryModelList.stream().filter(f -> f.getId().equals(pid)).collect(Collectors.toList());
            String shiftCode = collect1.get(0).getModelCode();

            return getData(factoryModelList, shiftCode, collect1.get(0).getModelType());
        }
        return factoryShifts;
    }

    /**
     * 返回当前时间段班次
     */
    private FactoryShift getProduction(List<FactoryShift> data) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //获取当前时间段
        Date date = new Date();
        FactoryShift factoryShift = null;
        //获取时间段
        String format = simpleDateFormat.format(date);
        for (FactoryShift datum : data) {
            FactoryShiftDto convert = ConvertUtil.convert(datum, FactoryShiftDto.class);
            //组装班次时间
            FactoryShiftDto factoryShiftDto = assembleClasses(convert);
            //开始时间
            String startTime = factoryShiftDto.getStartTime();
            //结束时间
            String endTime = factoryShiftDto.getEndTime();
            if (format.compareTo(startTime) >= 0 && format.compareTo(endTime) <= 0) {
                factoryShift = datum;
                break;
            }
        }
        if (factoryShift == null) {
            throw new RuntimeException("当前时间段不存在班次,请前往设置");
        }
        return factoryShift;
    }

    public FactoryShiftDto assembleClasses(FactoryShiftDto classes) {
        SimpleDateFormat sdf2 = new SimpleDateFormat("HH:mm");
        Date dNow = new Date();   //当前时间
        String format = sdf2.format(dNow);
        Date dBefore = new Date();
        Date frontData = new Date();
        Calendar calendar = Calendar.getInstance(); //得到日历
        calendar.setTime(dNow);//把当前时间赋给日历
        calendar.add(Calendar.DAY_OF_MONTH, 1);  //设置为后一天
        dBefore = calendar.getTime();   //得到前一天的时间
        calendar.setTime(dNow);
        calendar.add(Calendar.DAY_OF_MONTH, -1);  //设置为前一天
        frontData = calendar.getTime();   //得到前一天的时间
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); //设置时间格式
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //设置时间格式
        String defaultStartDate = sdf.format(dBefore);    //格式化后一天
        String defaultEndDate = sdf.format(dNow); //格式化当前时间
        String format1 = sdf.format(frontData);//格式化前一天
        //设置班组信息
        if ("1".equals(classes.getIsAcross())) {
            if (format.compareTo(classes.getStartTime()) >= 0) {
                //开始时间
                classes.setStartTime(defaultEndDate + " " + classes.getStartTime() + ":00");
                //结束时间
                classes.setEndTime(defaultStartDate + " " + classes.getEndTime() + ":00");
            } else {
                //开始时间
                classes.setStartTime(format1 + " " + classes.getStartTime() + ":00");
                //结束时间
                classes.setEndTime(defaultEndDate + " " + classes.getEndTime() + ":00");
            }

        } else {
            //开始时间
            classes.setStartTime(defaultEndDate + " " + classes.getStartTime() + ":00");
            //结束时间
            classes.setEndTime(defaultEndDate + " " + classes.getEndTime() + ":00");
        }
        return classes;
    }


    /**
     * 查看当前时间段是否存在班次
     */
    public void verificationData(List<FactoryShift> factoryShifts, FactoryShiftDto resources) {
        if (!CollectionUtils.isEmpty(factoryShifts)) {
            for (FactoryShift factoryShift : factoryShifts) {
                //拼装班次时间
                FactoryShiftDto convert = ConvertUtil.convert(factoryShift, FactoryShiftDto.class);
                convert = assembleClasses(convert);
                //拼装新增时间
                FactoryShiftDto convert1 = ConvertUtil.convert(resources, FactoryShiftDto.class);
                convert1 = assembleClasses(convert1);
                //判断
                //1.开始时间小于班次,结束时间大于开始时间,结束时间小于等于结束时间
                if (convert1.getStartTime().compareTo(convert.getStartTime()) < 0
                        && convert1.getEndTime().compareTo(convert.getStartTime()) > 0 && convert1.getEndTime().compareTo(convert.getEndTime()) <= 0) {
                    throw new RuntimeException("当前时间段以存在新增失败!");
                }
                //2.开始时间大于或等于开始时间,小于结束时间,结束时间大于或等于结束时间
                if (convert1.getStartTime().compareTo(convert.getStartTime()) >= 0
                        && convert1.getStartTime().compareTo(convert.getEndTime()) < 0 && convert1.getEndTime().compareTo(convert.getEndTime()) >= 0) {
                    throw new RuntimeException("当前时间段以存在新增失败!");
                }
                //3.开始时间小于开始时间,结束时间大于结束时间
                if (convert1.getStartTime().compareTo(convert.getStartTime()) < 0
                        && convert1.getEndTime().compareTo(convert.getEndTime()) > 0) {
                    throw new RuntimeException("当前时间段以存在新增失败!");
                }
                //4.开始时间大于开始时间,结束时间小于结束时间
                if (convert1.getStartTime().compareTo(convert.getStartTime()) > 0
                        && convert1.getEndTime().compareTo(convert.getEndTime()) < 0) {
                    throw new RuntimeException("当前时间段以存在新增失败!");
                }
            }
        }
    }

    /*
    private void delCaches(Integer id) {
        redisUtils.delByKey(CACHE_KEY + "::id:", id);
    }

    private void delCaches(Set<Integer> ids) {
        for (Integer id: ids) {
            delCaches(id);
        }
    }*/

    /*
    @Override
    public void download(List<FactoryShiftDto> all, HttpServletResponse response) throws IOException {
      List<Map<String, Object>> list = new ArrayList<>();
      for (FactoryShiftDto factoryShift : all) {
        Map<String,Object> map = new LinkedHashMap<>();
              map.put("班组ID", factoryShift.getTeamGroupId());
              map.put("班次编码", factoryShift.getShiftCode());
              map.put("班次名称", factoryShift.getShiftName());
              map.put("开始时间", factoryShift.getStartTime());
              map.put("结束时间", factoryShift.getEndTime());
              map.put("是否禁用 0：否，1：是", factoryShift.getIsDisable());
              map.put("备注说明", factoryShift.getRemark());
              map.put("创建人", factoryShift.getCreateBy());
              map.put("创建时间", factoryShift.getCreateTime());
              map.put("更新人", factoryShift.getUpdateBy());
              map.put("更新时间", factoryShift.getUpdateTime());
              map.put("所属模型", factoryShift.getTemplateCode());
        list.add(map);
      }
      FileUtil.downloadExcel(list, response);
    }*/
}
